package gl

import org.lwjgl.glfw.GLFW.*
import org.lwjgl.glfw.GLFWErrorCallback
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL11.glViewport
import org.lwjgl.opengl.GLCapabilities
import org.lwjgl.system.MemoryUtil.NULL

@Suppress("MemberVisibilityCanBePrivate")
class Window(private var _width: Int = 800, private var _height: Int = 600, private var _title: CharSequence = "Demo") {

    val windowId: Long
    val capabilities: GLCapabilities

    var width
        get() = _width
        set(value) {
            _width = value
            glfwSetWindowSize(windowId, _width, _height)
        }
    var height
        get() = _height
        set(value) {
            _height = value
            glfwSetWindowSize(windowId, _width, _height)
        }
    var title
        get() = _title
        set(value) {
            _title = value
            glfwSetWindowTitle(windowId, _title)
        }
    var closed: Boolean
        get() = glfwWindowShouldClose(windowId)
        set(value) {
            glfwSetWindowShouldClose(windowId, value)
            glfwDestroyWindow(windowId)
        }

    var onResize: ((width: Int, height: Int) -> Unit)? = null

    init {
        glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err))

        if (!glfwInit()) {
            throw RuntimeException("GLFW Init Error")
        }

        glfwDefaultWindowHints()
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE)
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4)
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0)

        windowId = glfwCreateWindow(width, height, title, NULL, NULL)
        if (windowId == NULL) {
            throw RuntimeException("GLFW Cannot create window: $title[$width X $height]")
        }
        glfwGetVideoMode(glfwGetPrimaryMonitor())
        glfwMakeContextCurrent(windowId)
        capabilities = GL.createCapabilities()
        glfwSwapInterval(1)

        glfwSetFramebufferSizeCallback(windowId) { _, width, height ->
            if (_width != width || _height != height) {
                _width = width
                _height = height
                glViewport(0, 0, width, height)
                onResize?.invoke(width, height)
            }
        }
    }

    fun start(update: () -> Boolean) {
        try {
            glfwShowWindow(windowId)
            while (!closed) {
                if (update()) {
                    closed = true
                }
                glfwSwapBuffers(windowId)
                glfwPollEvents()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}